/*
** servidor daemonizado
*/

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>

#define MYPORT 3477    
#define BACKLOG 10   
#define MAXDATASIZE 100
#define MAXFD 64
#define LOGPATH "083681srv.log"

void daemon_init (void);
void append_log  (struct sockaddr_in *cliente, int linhas_recebidas, int char_recebidos);

main()
{

  /* ---------------VARIAVEIS------------------ */
                                                //
  int sockfd, new_fd;                           //
  FILE *rsock, *wsock;                          //
  char buf[MAXDATASIZE];                        //
                                                //
  int linhas_recebidas=0, char_recebidos=0;     //
  int tam_linha;                                //
                                                //
  struct sockaddr_in my_addr;                   //
  struct sockaddr_in their_addr;                //
  int sin_size, numreads, numchar, x=0, yes=1;  //
                                                //
  // ------------------------------------------ //
  //
  /* ----------------------INICIALIZACAO----------------------------- */
                                                                      //
  /* DAEMON */                                                        //
  daemon_init();                                                      //
                                                                      //
  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {             //
    perror("socket");                                                 //
    exit(1);                                                          //
  }                                                                   //
                                                                      //
  setvbuf(wsock, NULL, _IOLBF, 0);                                    //
  setvbuf(rsock, NULL, _IOLBF, 0);                                    //
                                                                      //
  my_addr.sin_family      = AF_INET;                                  //
  my_addr.sin_port        = htons(MYPORT);                            //
  my_addr.sin_addr.s_addr = INADDR_ANY;                               //
  bzero(&(my_addr.sin_zero), 8);                                      //
                                                                      //
  if (bind(sockfd, (struct sockaddr *)&my_addr,                       //
	   sizeof(struct sockaddr)) == -1) {                          //
    perror("bind");                                                   //
    exit(1);                                                          //
  }                                                                   //
                                                                      //
  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,                    //
		 &yes, sizeof(int)) == -1) {                          //
    perror("setsockopt");                                             //
    exit(1);                                                          //
  }                                                                   //
                                                                      //
  if (listen(sockfd, BACKLOG) == -1) {                                //
    perror("listen");                                                 //
    exit(1);                                                          //
  }                                                                   //
                                                                      //
  // ---------------------------------------------------------------- //
  //
  /* ------------------------------ITERACOES--------------------------------------- */
                                                                                    //
  while(1) {                                                                        //
    sin_size = sizeof(struct sockaddr_in);                                          //
                                                                                    //
    if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr,                    //
			 &sin_size)) == -1) {                                       //
      perror("accept");                                                             //
      continue;                                                                     //
    }                                                                               // 
                                                                                    //
    if (!fork()) {                                                                  //
                                                                                    //
      linhas_recebidas = 0;                                                         //
      char_recebidos   = 0;                                                         //
                                                                                    //
      rsock = fdopen(new_fd, "r");                                                  //
      wsock = fdopen(new_fd, "w");                                                  //
                                                                                    //	
      while (fgets(buf, MAXDATASIZE, rsock)) {                                      //
                                                                                    //
	linhas_recebidas++;                                                         //
	char_recebidos  += strlen(buf);                                             //
                                                                                    //
	if (fputs(buf, wsock) == EOF) {                                             //
	  perror("fputs");                                                          //
	  exit(1);                                                                  //
	}                                                                           //
      }	                                                                            //
                                                                                    //
      log_append(&their_addr, linhas_recebidas, char_recebidos);                    //
                                                                                    //
      close(new_fd);                                                                //
      exit(1);                                                                      // 
    }                                                                               //
  }                                                                                 //
                                                                                    //
  // ------------------------------------------------------------------------------ //

  return 0;
}

/* -------------FUNCOES AUXILIARES------------- */

void daemon_init(void) {
  int i;
    
  /* mata 1o pai */
  if (fork())
    exit(0);               
    
  /* seta 1o filho como lider */
  setsid();                   
  signal(SIGHUP, SIG_IGN);    
    
  /* mata 1o filho */
  if (fork())
    exit(0);              
    
  /* muda o diretorio de trabalho */
  chdir("/tmp"); 
  umask(0);     
    
  /* fecha todos descritores de arquivos */
  for (i = 0; i < MAXFD; i++) 
    close(i);
 
  return;
}

void log_append(struct sockaddr_in *cliente, int linhas_recebidas, int char_recebidos) {
  FILE *log;

  log = fopen(LOGPATH, "a");
  
  fprintf(log,"cliente: %s\n", inet_ntoa(cliente->sin_addr));
  fprintf(log,"linhas recebidas: %d\n", linhas_recebidas);
  fprintf(log,"carac. recebidos: %d\n", char_recebidos);
  fprintf(log,"--------------------------------------\n");

  return;
}
